package com.tyf.common.util;

import com.alibaba.fastjson.annotation.JSONField;
import com.tyf.common.annotation.BaseDataCache;
import com.tyf.common.constant.Fetches;
import com.tyf.common.constant.Regexes;
import com.tyf.common.vo.ResultVO;
import com.tyf.common.annotation.ApiFetch;
import com.tyf.common.annotation.PartitionEntity;
import com.tyf.common.constant.DateFormats;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.BigIntegerConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * Description: 公共工具类 
 * author: mokeo 
 * Createdate: 2016年9月25日上午11:47:54
 */
// @SuppressWarnings({ "rawtypes", "unchecked" })
// 请不要对整个类压制警告，因为这样可能会掩盖了一些重要的警告
// 尽量小范围的压制，且需要对压制警告处增加备注 effctive java n24
public class CommonUtils {
	private CommonUtils() {
	}

	/**
	 * 获取默认的resultMap
	 * @return
	 */
	public static Map<String, Object> getDefaultResultMap() {
		Map<String, Object> resultMap = new HashMap<>();
		ResultVO flag = new ResultVO();

		resultMap.put("flag", flag);
		return resultMap;
	}
	
	/**
	 * 获取带返回信息的resultMap
	 * @param retMsg
	 * @return
	 */
	public static Map<String, Object>  getDefaultResultMap(String retMsg){
		Map<String, Object> resultMap = new HashMap<>();
		
		ResultVO flag = new ResultVO();
		flag.setRetMsg(retMsg);
		resultMap.put("flag", flag);
		
		return resultMap;
	}

	/**
	 * 对字符串进行MD5加密
	 * 
	 * @param plainText
	 *            String
	 * @return String
	 */
	public static String md5(String plainText) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(plainText.getBytes());
			byte b[] = md.digest();
			int i;
			StringBuffer buf = new StringBuffer("");
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0) {
					i += 256;
				}
				if (i < 16) {
					buf.append("0");
				}
				buf.append(Integer.toHexString(i));
			}
			return buf.toString();
		} catch (NoSuchAlgorithmException e) {
			// e.printStackTrace();
			return "";
		}
	}

	/**
	 * 文件或url扩展名是否为指定的扩展名
	 * 
	 * @param fileName
	 * @param extension
	 * @return
	 */
	public static boolean isExtension(String fileName, String extension) {
		return (extension.equalsIgnoreCase(CommonUtils.getFileExtension(fileName))) ? true : false;
	}

	/**
	 * 获取文件或url扩展名
	 * 
	 * @param fileName、url
	 * @return
	 */
	public static String getFileExtension(String fileName) {
		if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) {
			return fileName.substring(fileName.lastIndexOf(".") + 1);
		} else {
			return "";
		}
	}

	/**
	 * javabean驼峰格式转下划线格式 如：testName test_name
	 * 
	 * @param javeBeanStr
	 * @return
	 */
	public static String convertJaveBeanStrToUnderLine(String javeBeanStr) {
		StringBuffer buf = new StringBuffer();
		Pattern p = Pattern.compile("[A-Z]");
		Matcher m = p.matcher(javeBeanStr);
		while (m.find()) {
			m.appendReplacement(buf, "_" + m.group(0));
		}
		m.appendTail(buf);
		return buf.toString().toLowerCase();
	}

	/**
	 * 下划线格式转javabean驼峰格式 如： test_name testName
	 * 
	 * @param underLineStr
	 * @return
	 */
	public static String convertUnderLineStrToJaveBean(String underLineStr) {
		StringBuffer buf = new StringBuffer(underLineStr);
		Matcher mc = Pattern.compile("_").matcher(underLineStr);
		int i = 0;
		while (mc.find()) {
			int position = mc.end() - (i++);
			// 如果'_'为最后的字符,则直接退出循环,解决db2中'rownumber_'字符串数组越界问题
			if (position == underLineStr.length()) {
				break;
			}
			buf.replace(position - 1, position + 1, buf.substring(position, position + 1).toUpperCase());
		}
		return buf.toString();
	}

	public static void object2MapWithoutNull(Object obj, Map map)
			throws IllegalArgumentException, IllegalAccessException {
		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
			Field[] fields = superClass.getDeclaredFields();
			for (int j = 0; j < fields.length; j++) {
				fields[j].setAccessible(true);
				String fieldName = fields[j].getName();
				Object fieldValue = fields[j].get(obj);

				// 针对子类与父类中存在同样field的情况，直接以子类中的值为准，避免子类的值被父类所覆盖
				if(map.get(fieldName) != null){
					continue;
				}

				if (fieldValue != null) {
					if ((fieldValue instanceof Date)) {
						boolean jfFalge = fields[j].isAnnotationPresent(JSONField.class);
						if (jfFalge) {
							JSONField jf = (JSONField) fields[j].getAnnotation(JSONField.class);
							SimpleDateFormat sdf = new SimpleDateFormat(jf.format());
							map.put(fieldName, sdf.format(fieldValue));
						} else {
							SimpleDateFormat sdf = new SimpleDateFormat(DateFormats.DF1_16);
							map.put(fieldName, sdf.format(fieldValue));
						}
					} else {
						map.put(fieldName, fieldValue);
					}
				} else {
					map.put(fieldName, "");
				}
			}
		}
	}
	
	/**
	 * 获取UUID，去除连接符
	 * @return
	 */
	public static String getUUIDWithNoConcat() {
		UUID uuid = UUID.randomUUID();
		String str = uuid.toString();
		return str.replaceAll("-", "");
	}
	
	/**
	 * 返回指定长度uuid
	 * @param length 长度
	 * @return
	 */
	/**
	 * 获取UUID，去除连接符
	 * @return
	 */
	public static String getUUIDWithNoConcat(int length) {
		UUID uuid = UUID.randomUUID();
		String str = uuid.toString();
		return str.replaceAll("-", "").substring(0, length);
	}
	
	/**
	 * 获取总计列list
	 * @param list
	 * @return
	 */
	public static List getSummaryList(List list){
		List retList = Lists.newArrayList();
		
		Map<String, Object> m = Maps.newHashMap();
		String[] sumProperties = ThreadLocals.getSumPropertys().split(",");
		int i = 0;
		if(sumProperties.length == 1){
			Object sumValue = list.get(0);
			m.put(sumProperties[0], sumValue==null ? 0:sumValue);
		}else{
			for(String s : sumProperties){		//多列返回的结构为list的Object[x]对象
				Object sumValue = ((Object[])list.get(0))[i++];
				m.put(s, sumValue==null ? 0:sumValue);
			}
		}
		retList.add(m);
		
		return retList;
	}
	
	/**
	 * 设置对象属性值，不管设置值的类型，主要针对数值属性的设置
	 * @param sourceObj 对象
	 * @param propertyName	对象属性
	 * @param inputValue	设置值
	 */
	public static void setValueByAnyType(Object sourceObj, String propertyName, Object inputValue){
		setValueByAnyType(sourceObj, propertyName, inputValue, false);
	}

	public static void setValueByAnyType(Object sourceObj, String propertyName, Object inputValue, boolean ignoreNotFound){
		Object newValue = inputValue;
		String newPropertyName = convertUnderLineStrToJaveBean(propertyName);	//若为下划线'_',则自动转为大小,原生sql可以不用设别名
		Field f = ReflectUtils.getAccessibleField(sourceObj, newPropertyName);
		if(f == null){
			if(ignoreNotFound){
				return;
			}
			throw new RuntimeException("propertyName["+ propertyName +"] not in the vo class[" + sourceObj.getClass() + "]");
		}
		Class expectedType = f.getType();
		if(inputValue!=null && expectedType!=null && !expectedType.isAssignableFrom(inputValue.getClass())){
			newValue = convertValue(expectedType, inputValue);
		}
		ReflectUtils.invokeSetter(sourceObj, newPropertyName, newValue);
	}
	
	/**
	 * 转换为指定类型的value对象，主要为数值类型
	 * @param expectedType 期望类型当前只考虑了数值类型
	 * @param value 输入值
	 * @return
	 */
	public static Object convertValue(Class<?> expectedType, Object value){
		// 若为枚举类型，则转换为枚举对象
		if(expectedType.isEnum()){
			return EnumUtils.getEnum((Class<? extends Enum>)expectedType, value.toString());
		}
		String expectedTypeName = expectedType.getName();
		if(expectedTypeName.contains("Long")){
			return Long.valueOf(value.toString());
		}else if(expectedTypeName.contains("Integer") || expectedTypeName.contains("int")){
			return new IntegerConverter().convert(expectedType, value);
		}else if(expectedTypeName.contains("String")){
			return value.toString();
		}else if(expectedTypeName.contains("BigInteger")){
			return new BigIntegerConverter().convert(expectedType, value);
		}else if(expectedTypeName.contains("BigDecimal")){
			return new BigDecimalConverter().convert(expectedType, value);
		}else if(expectedTypeName.contains("Decimal")){
			return new BigDecimalConverter().convert(expectedType, value);
		}else{
			return value;
		}
		
	}
	
	/**
	 * 判断是否为整数
	 * @param s
	 * @return
	 */
	public static boolean isInteger(String s){
		// 正则初始化
		Pattern p = Pattern.compile(Regexes.INTEGER);
		// 匹配器初始化
		Matcher m = p.matcher(s);
		return m.matches();
	}
	
	/**
	 * 判断是否为浮点数
	 * @param s
	 * @return
	 */
	public static boolean isDecimal(String s){
		// 正则初始化
		Pattern p = Pattern.compile(Regexes.DECIMAL);
		// 匹配器初始化
		Matcher m = p.matcher(s);
		return m.matches();
	}
	
	/*
	 * 判断是否为日期格式 yyyy-MM-dd yyyy/MM/dd
	 */
	public static boolean isDF_8(String s){
		Pattern p = Pattern.compile(Regexes.DF_8);
		Matcher m = p.matcher(s);
		return m.matches();
	}
	
	public static String handleMultiCondition(Object obj){
		if (obj instanceof Object[]) {
			StringBuilder sb = new StringBuilder();
			Object[] strs = (Object[])obj;
			for (int i = 0; i < strs.length; i++) {
				if (i == strs.length-1) {
					sb.append("'"+strs[i]+"'");
				}else{
					sb.append("'"+strs[i]+"',");
				}
			}
			return sb.toString();
		}
		return null;
	}
	
	/**
	 * 获取类上面的ApiFetch的注解元数据Map
	 * @param clazz 类
	 * @return map 其中key-ApiFetch, value-field
	 * 		对于同样的注解，field多个则以','分隔，如"materialCode,materialName"
	 * 		可以实现对象复用
	 */
	public static Map<ApiFetch, String> getApiFectchMetaData(Class<?> clazz){
		Map<ApiFetch, String> metaData = Maps.newHashMap();
		// TODO: 考虑同一api服务需获取多次，对应vo中两个不同字段都需要做关联；
		// 如一个vo中存在大类，小类，这两者的值并不是从一个对象获取，需关联两次

		for (Field f : clazz.getDeclaredFields()) {
			if(f.isAnnotationPresent(ApiFetch.class)){
				ApiFetch apiFetch = f.getAnnotation(ApiFetch.class);
				// 判断apiFetch注解是否有效
				if(ArrayUtils.isEmpty(apiFetch.joinField()) 
						|| (apiFetch.apiClass()==void.class && StringUtils.isEmpty(apiFetch.apiName()))){
					throw new IllegalArgumentException("annotation ApiFetch.class is illegal, joinField && (apiName||apiClass) can not be empty");
				}
				// 如果映射字段不为空,则放入field中,后续的handel中会根据映射关系进行处理
				String curName = f.getName();
				if (StringUtils.isNotEmpty(apiFetch.mappedName())){
					curName += ":" + apiFetch.mappedName();
				}
				// 对于一个类中，同样的注解，其实对应的是一个外关联的obj不同属性，则使用","分隔多
				String existField = metaData.get(apiFetch);
				if(StringUtils.isNotEmpty(existField)){
					metaData.put(apiFetch, existField + "," + curName);
				}else{
					metaData.put(apiFetch, curName);
				}
			}
		}
		
		return metaData;
	}
	

	/**
	 * 多字段；源对象，目标对象；目标对象值设置
	 * @param sourceObj
	 * @param targetObj
	 * @param fieldNames
	 */
	private static void setFieldValues(Object sourceObj, Object targetObj, String[] fieldNames){
		for(String s: fieldNames){
			String field = s;
			String mappedName = s;
			int index = s.indexOf(":");
			if(index > 0){
				field = s.substring(0, index);
				mappedName = s.substring(index+1);
			}

			Object fieldValue = ReflectUtils.invokeGetter(sourceObj, mappedName);
			ReflectUtils.invokeSetter(targetObj, field, fieldValue);
		}
	}
	
	/**
	 * 判断属性是否是数字类型
	 * @param fieldName
	 * @return
	 */
	public static boolean fieldIsNumber(Class<?> clazz, String fieldName){
		Field[] fields = clazz.getDeclaredFields();
		for(int i=0;i<fields.length;i++){
			if(fields[i].getName().equals(fieldName)){
				String typeName= fields[i].getType().toString();
				if(isNumberType(typeName))return true;
			}
		}
		Field[] fields1 = clazz.getSuperclass().getDeclaredFields();
		for(int i=0;i<fields1.length;i++){
			if(fields1[i].getName().equals(fieldName)){
				String typeName= fields1[i].getType().toString();
				if(isNumberType(typeName))return true;
			}
		}
		return false;
	}
	
	private static boolean isNumberType(String typeName){
		if(typeName.contains("Integer") || typeName.contains("int") 
				|| typeName.contains("Double") || typeName.contains("double")
				|| typeName.contains("Long") || typeName.contains("long")
				|| typeName.contains("BigDecimal")
				|| typeName.contains("Short") || typeName.contains("short")){
			return true;
		}
		return false;
	}

	/**
	 * 获取异常的堆栈信息
	 *
	 * @param t
	 * @return
	 */
	public static String getStackTrace(Throwable t) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);

		try {
			t.printStackTrace(pw);
			return sw.toString();
		} finally {
			pw.close();
		}
	}

	/**
	 * 获取实体分库属性
	 * @param entityClazz
	 * @return
	 */
	public static String getEntityPartitionBy(Class entityClazz){
		String partitionBy = "";
		PartitionEntity peAnntation = (PartitionEntity)entityClazz.getAnnotation(PartitionEntity.class);
		if(peAnntation != null){
			// partitionBy不是默认值则取partitionBy，否则取value
			partitionBy = peAnntation.partitionBy().equals(PartitionEntity.DEFAULT_PARTITIONBY) ? peAnntation.value():peAnntation.partitionBy();
		}
		return partitionBy;
	}

	public static BaseDataCache getBaseDataCacheAnonotaton(Class entityClazz){
		return (BaseDataCache)entityClazz.getAnnotation(BaseDataCache.class);
	}

	public static void main(String[] args){
//		System.out.println(convertJaveBeanStrToUnderLine("lineCode"));
//		try {
//			int v = 1/0;
//		}catch (Exception e){
//			System.out.println("message: " + e.getMessage());
//			System.out.println("cause: " + e.getCause());
//			System.out.println("stackTrace: " + getStackTrace(e));
//		}
		String s = "nae:2323";
		String mappedName = s;
		String field = s;
		int index = s.indexOf(":");
		if(index > 0){
			field = s.substring(0, index);
			mappedName = s.substring(index+1);
		}
		System.out.println(field);
		System.out.println(mappedName);

	}

}
